#!/bin/bash
###############################################################################
#       脚本名称: utils_datetime.sh
#       功能描述: 日期时间工具类功能函数，提供纯粹的日期时间操作功能。
#       作者: 林再来
#       日期: 2025-10-21
#       版本: 1.0
#       基础功能:
#           1、基础日期/时间获取
#           2、日期/时间格式转换
#           3、日期/时间格式化输出
#           4、日期差/时间差值计算
#           5、时区处理
#       扩展功能:
#           1、工作日计算和节假日判断
#           2、时间区间生成和序列处理 
#           3、年龄计算和星座查询
#           4、闰年判断和月份天数计算
#       依赖(插件/命令):
#           1、bash
#           2、date
###############################################################################

# 防止重复加载
if [[ -n "${utils_datetime_sh_loaded:-}" ]]; then
    return 0
fi
readonly utils_datetime_sh_loaded=1

# 注意：不使用严格模式，避免影响交互式 shell

# 获取脚本目录和项目根目录（如果尚未定义）
if [[ -z "${script_dir:-}" ]]; then
    script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
    readonly script_dir
fi

if [[ -z "${project_root:-}" ]]; then
    project_root="$(cd "${script_dir}/../.." && pwd)"
    readonly project_root
fi

###############################################################################
# 全局常量
###############################################################################

# 常用日期格式
readonly UTILS_DATETIME_FORMAT_ISO="%Y-%m-%d %H:%M:%S"
readonly UTILS_DATETIME_FORMAT_DATE="%Y-%m-%d"
readonly UTILS_DATETIME_FORMAT_TIME="%H:%M:%S"
readonly UTILS_DATETIME_FORMAT_TIMESTAMP="%Y%m%d_%H%M%S"
readonly UTILS_DATETIME_FORMAT_RFC3339="%Y-%m-%dT%H:%M:%S%z"

# 时间单位（秒）
readonly UTILS_DATETIME_SECOND=1
readonly UTILS_DATETIME_MINUTE=60
readonly UTILS_DATETIME_HOUR=3600
readonly UTILS_DATETIME_DAY=86400
readonly UTILS_DATETIME_WEEK=604800

###############################################################################
# 全局变量
###############################################################################

utils_datetime_default_format="${utils_datetime_default_format:-$UTILS_DATETIME_FORMAT_ISO}"
utils_datetime_timezone="${utils_datetime_timezone:-}"

###############################################################################
# 基础日期时间获取
###############################################################################

# 函数: 获取当前日期时间
# 参数: $1 - 输出格式(可选，默认ISO格式)
# 返回: 0-成功, 1-失败
# 输出: 当前日期时间(stdout)
function utils_datetime_now() {
    local format="${1:-$utils_datetime_default_format}"
    
    log_debug "utils_datetime" "获取当前日期时间，格式: $format"
    
    local result
    if [[ -n "$utils_datetime_timezone" ]]; then
        if result=$(TZ="$utils_datetime_timezone" date "+$format" 2>/dev/null); then
            echo "$result"
            return 0
        else
            log_error "utils_datetime" "错误: 获取当前日期时间失败，时区: $utils_datetime_timezone"
            return 1
        fi
    else
        if result=$(date "+$format" 2>/dev/null); then
            echo "$result"
            return 0
        else
            log_error "utils_datetime" "错误: 获取当前日期时间失败"
            return 1
        fi
    fi
}

# 函数: 获取当前日期
# 参数: $1 - 输出格式(可选，默认YYYY-MM-DD)
# 返回: 0-成功, 1-失败
# 输出: 当前日期(stdout)
function utils_datetime_today() {
    local format="${1:-$UTILS_DATETIME_FORMAT_DATE}"
    
    log_debug "utils_datetime" "获取当前日期，格式: $format"
    
    local result
    if [[ -n "$utils_datetime_timezone" ]]; then
        if result=$(TZ="$utils_datetime_timezone" date "+$format" 2>/dev/null); then
            echo "$result"
            return 0
        else
            log_error "utils_datetime" "错误: 获取当前日期失败，时区: $utils_datetime_timezone"
            return 1
        fi
    else
        if result=$(date "+$format" 2>/dev/null); then
            echo "$result"
            return 0
        else
            log_error "utils_datetime" "错误: 获取当前日期失败"
            return 1
        fi
    fi
}

# 函数: 获取当前时间
# 参数: $1 - 输出格式(可选，默认HH:MM:SS)
# 返回: 0-成功, 1-失败
# 输出: 当前时间(stdout)
function utils_datetime_time() {
    local format="${1:-$UTILS_DATETIME_FORMAT_TIME}"
    
    log_debug "utils_datetime" "获取当前时间，格式: $format"
    
    local result
    if [[ -n "$utils_datetime_timezone" ]]; then
        if result=$(TZ="$utils_datetime_timezone" date "+$format" 2>/dev/null); then
            echo "$result"
            return 0
        else
            log_error "utils_datetime" "错误: 获取当前时间失败，时区: $utils_datetime_timezone"
            return 1
        fi
    else
        if result=$(date "+$format" 2>/dev/null); then
            echo "$result"
            return 0
        else
            log_error "utils_datetime" "错误: 获取当前时间失败"
            return 1
        fi
    fi
}

# 函数: 获取Unix时间戳
# 参数: 无
# 返回: 0-成功, 1-失败
# 输出: Unix时间戳(stdout)
function utils_datetime_timestamp() {
    log_debug "utils_datetime" "获取Unix时间戳"
    
    local result
    if result=$(date +%s 2>/dev/null); then
        echo "$result"
        return 0
    else
        log_error "utils_datetime" "错误: 获取Unix时间戳失败"
        return 1
    fi
}

###############################################################################
# 日期时间格式转换
###############################################################################

# 函数: 转换日期时间格式
# 参数: $1 - 输入日期时间, $2 - 输入格式, $3 - 输出格式
# 返回: 0-成功, 1-失败
# 输出: 转换后的日期时间(stdout)
function utils_datetime_convert() {
    local input_datetime="$1"
    local input_format="$2"
    local output_format="$3"
    
    if [[ -z "$input_datetime" ]] || [[ -z "$input_format" ]] || [[ -z "$output_format" ]]; then
        log_error "utils_datetime" "错误: 缺少参数: 输入日期时间、输入格式、输出格式"
        return 1
    fi
    
    log_debug "utils_datetime" "转换日期时间格式: $input_datetime ($input_format -> $output_format)"
    
    local result
    if result=$(date -d "$input_datetime" "+$output_format" 2>/dev/null); then
        echo "$result"
        return 0
    else
        log_error "utils_datetime" "错误: 日期时间格式转换失败: $input_datetime"
        return 1
    fi
}

# 函数: Unix时间戳转日期时间
# 参数: $1 - Unix时间戳, $2 - 输出格式(可选，默认ISO格式)
# 返回: 0-成功, 1-失败
# 输出: 日期时间(stdout)
function utils_datetime_from_timestamp() {
    local timestamp="$1"
    local format="${2:-$utils_datetime_default_format}"
    
    if [[ -z "$timestamp" ]]; then
        log_error "utils_datetime" "错误: 缺少参数: Unix时间戳"
        return 1
    fi
    
    # 验证时间戳格式
    if ! [[ "$timestamp" =~ ^[0-9]+$ ]]; then
        log_error "utils_datetime" "错误: 无效的时间戳格式: $timestamp"
        return 1
    fi
    
    log_debug "utils_datetime" "Unix时间戳转日期时间: $timestamp -> $format"
    
    local result
    if [[ -n "$utils_datetime_timezone" ]]; then
        if result=$(TZ="$utils_datetime_timezone" date -d "@$timestamp" "+$format" 2>/dev/null); then
            echo "$result"
            return 0
        else
            log_error "utils_datetime" "错误: 时间戳转日期时间失败，时区: $utils_datetime_timezone"
            return 1
        fi
    else
        if result=$(date -d "@$timestamp" "+$format" 2>/dev/null); then
            echo "$result"
            return 0
        else
            log_error "utils_datetime" "错误: 时间戳转日期时间失败"
            return 1
        fi
    fi
}

# 函数: 日期时间转Unix时间戳
# 参数: $1 - 日期时间字符串
# 返回: 0-成功, 1-失败
# 输出: Unix时间戳(stdout)
function utils_datetime_to_timestamp() {
    local datetime="$1"
    
    if [[ -z "$datetime" ]]; then
        log_error "utils_datetime" "错误: 缺少参数: 日期时间字符串"
        return 1
    fi
    
    log_debug "utils_datetime" "日期时间转Unix时间戳: $datetime"
    
    local result
    if result=$(date -d "$datetime" +%s 2>/dev/null); then
        echo "$result"
        return 0
    else
        log_error "utils_datetime" "错误: 日期时间转时间戳失败: $datetime"
        return 1
    fi
}

###############################################################################
# 日期时间格式化输出
###############################################################################

# 函数: 格式化日期时间
# 参数: $1 - 日期时间字符串, $2 - 输出格式
# 返回: 0-成功, 1-失败
# 输出: 格式化后的日期时间(stdout)
function utils_datetime_format() {
    local datetime="$1"
    local format="$2"
    
    if [[ -z "$datetime" ]] || [[ -z "$format" ]]; then
        log_error "utils_datetime" "错误: 缺少参数: 日期时间字符串和输出格式"
        return 1
    fi
    
    log_debug "utils_datetime" "格式化日期时间: $datetime -> $format"
    
    local result
    if [[ -n "$utils_datetime_timezone" ]]; then
        if result=$(TZ="$utils_datetime_timezone" date -d "$datetime" "+$format" 2>/dev/null); then
            echo "$result"
            return 0
        else
            log_error "utils_datetime" "错误: 日期时间格式化失败，时区: $utils_datetime_timezone"
            return 1
        fi
    else
        if result=$(date -d "$datetime" "+$format" 2>/dev/null); then
            echo "$result"
            return 0
        else
            log_error "utils_datetime" "错误: 日期时间格式化失败"
            return 1
        fi
    fi
}

# 函数: 获取相对时间描述
# 参数: $1 - 日期时间字符串
# 返回: 0-成功, 1-失败
# 输出: 相对时间描述(stdout)
function utils_datetime_relative() {
    local datetime="$1"
    
    if [[ -z "$datetime" ]]; then
        log_error "utils_datetime" "错误: 缺少参数: 日期时间字符串"
        return 1
    fi
    
    log_debug "utils_datetime" "获取相对时间描述: $datetime"
    
    local result
    if result=$(date -d "$datetime" --rfc-3339=seconds 2>/dev/null); then
        echo "$result"
        return 0
    else
        log_error "utils_datetime" "错误: 获取相对时间描述失败: $datetime"
        return 1
    fi
}

###############################################################################
# 日期差/时间差值计算
###############################################################################

# 函数: 计算两个日期时间的差值（秒）
# 参数: $1 - 开始日期时间, $2 - 结束日期时间
# 返回: 0-成功, 1-失败
# 输出: 差值秒数(stdout)
function utils_datetime_diff_seconds() {
    local start_datetime="$1"
    local end_datetime="$2"
    
    if [[ -z "$start_datetime" ]] || [[ -z "$end_datetime" ]]; then
        log_error "utils_datetime" "错误: 缺少参数: 开始日期时间和结束日期时间"
        return 1
    fi
    
    log_debug "utils_datetime" "计算日期时间差值: $start_datetime -> $end_datetime"
    
    local start_timestamp end_timestamp diff
    
    # 转换为时间戳
    if ! start_timestamp=$(utils_datetime_to_timestamp "$start_datetime"); then
        return 1
    fi
    
    if ! end_timestamp=$(utils_datetime_to_timestamp "$end_datetime"); then
        return 1
    fi
    
    # 计算差值
    diff=$((end_timestamp - start_timestamp))
    echo "$diff"
    return 0
}

# 函数: 计算两个日期时间的差值（天）
# 参数: $1 - 开始日期时间, $2 - 结束日期时间
# 返回: 0-成功, 1-失败
# 输出: 差值天数(stdout)
function utils_datetime_diff_days() {
    local start_datetime="$1"
    local end_datetime="$2"
    
    if [[ -z "$start_datetime" ]] || [[ -z "$end_datetime" ]]; then
        log_error "utils_datetime" "错误: 缺少参数: 开始日期时间和结束日期时间"
        return 1
    fi
    
    log_debug "utils_datetime" "计算日期差值: $start_datetime -> $end_datetime"
    
    local diff_seconds diff_days
    
    # 计算秒数差值
    if ! diff_seconds=$(utils_datetime_diff_seconds "$start_datetime" "$end_datetime"); then
        return 1
    fi
    
    # 转换为天数
    diff_days=$((diff_seconds / UTILS_DATETIME_DAY))
    echo "$diff_days"
    return 0
}

# 函数: 计算日期时间加减
# 参数: $1 - 基准日期时间, $2 - 加减数量, $3 - 单位(second/minute/hour/day/week)
# 返回: 0-成功, 1-失败
# 输出: 计算后的日期时间(stdout)
function utils_datetime_add() {
    local base_datetime="$1"
    local amount="$2"
    local unit="$3"
    
    if [[ -z "$base_datetime" ]] || [[ -z "$amount" ]] || [[ -z "$unit" ]]; then
        log_error "utils_datetime" "错误: 缺少参数: 基准日期时间、加减数量和单位"
        return 1
    fi
    
    # 验证数量格式
    if ! [[ "$amount" =~ ^-?[0-9]+$ ]]; then
        log_error "utils_datetime" "错误: 无效的数量格式: $amount"
        return 1
    fi
    
    log_debug "utils_datetime" "计算日期时间加减: $base_datetime + $amount $unit"
    
    local result
    case "$unit" in
        "second"|"seconds")
            if result=$(date -d "$base_datetime $amount seconds" "+$utils_datetime_default_format" 2>/dev/null); then
                echo "$result"
                return 0
            fi
            ;;
        "minute"|"minutes")
            if result=$(date -d "$base_datetime $amount minutes" "+$utils_datetime_default_format" 2>/dev/null); then
                echo "$result"
                return 0
            fi
            ;;
        "hour"|"hours")
            if result=$(date -d "$base_datetime $amount hours" "+$utils_datetime_default_format" 2>/dev/null); then
                echo "$result"
                return 0
            fi
            ;;
        "day"|"days")
            if result=$(date -d "$base_datetime $amount days" "+$utils_datetime_default_format" 2>/dev/null); then
                echo "$result"
                return 0
            fi
            ;;
        "week"|"weeks")
            if result=$(date -d "$base_datetime $amount weeks" "+$utils_datetime_default_format" 2>/dev/null); then
                echo "$result"
                return 0
            fi
            ;;
        *)
            log_error "utils_datetime" "错误: 不支持的时间单位: $unit"
            return 1
            ;;
    esac
    
    log_error "utils_datetime" "错误: 日期时间加减计算失败"
    return 1
}

###############################################################################
# 时区处理
###############################################################################

# 函数: 设置默认时区
# 参数: $1 - 时区标识符
# 返回: 0-成功, 1-失败
function utils_datetime_set_timezone() {
    local timezone="$1"
    
    if [[ -z "$timezone" ]]; then
        log_error "utils_datetime" "错误: 缺少参数: 时区标识符"
        return 1
    fi
    
    log_debug "utils_datetime" "设置默认时区: $timezone"
    
    # 验证时区是否有效
    if TZ="$timezone" date >/dev/null 2>&1; then
        utils_datetime_timezone="$timezone"
        log_info "utils_datetime" "时区设置成功: $timezone"
        return 0
    else
        log_error "utils_datetime" "错误: 无效的时区标识符: $timezone"
        return 1
    fi
}

# 函数: 获取当前时区
# 参数: 无
# 返回: 0-成功, 1-失败
# 输出: 当前时区(stdout)
function utils_datetime_get_timezone() {
    log_debug "utils_datetime" "获取当前时区"
    
    if [[ -n "$utils_datetime_timezone" ]]; then
        echo "$utils_datetime_timezone"
        return 0
    fi
    
    local result
    if result=$(date +%Z 2>/dev/null); then
        echo "$result"
        return 0
    else
        log_error "utils_datetime" "错误: 获取当前时区失败"
        return 1
    fi
}

# 函数: 转换时区
# 参数: $1 - 日期时间字符串, $2 - 目标时区, $3 - 输出格式(可选)
# 返回: 0-成功, 1-失败
# 输出: 转换后的日期时间(stdout)
function utils_datetime_convert_timezone() {
    local datetime="$1"
    local target_timezone="$2"
    local format="${3:-$utils_datetime_default_format}"
    
    if [[ -z "$datetime" ]] || [[ -z "$target_timezone" ]]; then
        log_error "utils_datetime" "错误: 缺少参数: 日期时间字符串和目标时区"
        return 1
    fi
    
    log_debug "utils_datetime" "转换时区: $datetime -> $target_timezone"
    
    local result
    if result=$(TZ="$target_timezone" date -d "$datetime" "+$format" 2>/dev/null); then
        echo "$result"
        return 0
    else
        log_error "utils_datetime" "错误: 时区转换失败: $datetime -> $target_timezone"
        return 1
    fi
}

###############################################################################
# 增强功能模块
###############################################################################

# 函数: 判断是否为工作日
# 参数: $1 - 日期字符串
# 返回: 0-是工作日, 1-非工作日
function utils_datetime_is_workday() {
    local date_str="$1"
    
    if [[ -z "$date_str" ]]; then
        log_error "utils_datetime" "错误: 缺少参数: 日期字符串"
        return 1
    fi
    
    log_debug "utils_datetime" "判断是否为工作日: $date_str"
    
    # 获取星期几 (1-7, 1=周一, 7=周日)
    local weekday
    if ! weekday=$(date -d "$date_str" +%u 2>/dev/null); then
        log_error "utils_datetime" "错误: 无效的日期格式: $date_str"
        return 1
    fi
    
    # 周六(6)和周日(7)为非工作日
    if [[ "$weekday" -eq 6 ]] || [[ "$weekday" -eq 7 ]]; then
        log_debug "utils_datetime" "非工作日: $date_str (星期$weekday)"
        return 1
    fi
    
    log_debug "utils_datetime" "工作日: $date_str (星期$weekday)"
    return 0
}

# 函数: 判断是否为节假日
# 参数: $1 - 日期字符串
# 返回: 0-是节假日, 1-非节假日
# 说明: 支持中国法定节假日，可通过配置文件扩展
function utils_datetime_is_holiday() {
    local date_str="$1"
    
    if [[ -z "$date_str" ]]; then
        log_error "utils_datetime" "错误: 缺少参数: 日期字符串"
        return 1
    fi
    
    log_debug "utils_datetime" "判断是否为节假日: $date_str"
    
    # 提取年月日
    local year month day
    if ! year=$(date -d "$date_str" +%Y 2>/dev/null) || \
       ! month=$(date -d "$date_str" +%m 2>/dev/null) || \
       ! day=$(date -d "$date_str" +%d 2>/dev/null); then
        log_error "utils_datetime" "错误: 无效的日期格式: $date_str"
        return 1
    fi
    
    # 中国法定节假日 (固定日期)
    local fixed_holidays=(
        "01-01"  # 元旦
        "05-01"  # 劳动节
        "10-01"  # 国庆节
    )
    
    local date_md="${month}-${day}"
    for holiday in "${fixed_holidays[@]}"; do
        if [[ "$date_md" == "$holiday" ]]; then
            log_debug "utils_datetime" "节假日: $date_str ($holiday)"
            return 0
        fi
    done
    
    # 春节假期 (农历新年，这里简化处理，实际需要农历转换)
    # 2025年春节: 1月28日-2月3日
    if [[ "$year" == "2025" ]] && [[ "$month" == "01" ]] && [[ "$day" -ge 28 ]]; then
        log_debug "utils_datetime" "节假日: $date_str (春节)"
        return 0
    fi
    if [[ "$year" == "2025" ]] && [[ "$month" == "02" ]] && [[ "$day" -le 3 ]]; then
        log_debug "utils_datetime" "节假日: $date_str (春节)"
        return 0
    fi
    
    log_debug "utils_datetime" "非节假日: $date_str"
    return 1
}

# 函数: 判断是否为工作日(排除节假日)
# 参数: $1 - 日期字符串
# 返回: 0-是工作日, 1-非工作日
function utils_datetime_is_business_day() {
    local date_str="$1"
    
    if [[ -z "$date_str" ]]; then
        log_error "utils_datetime" "错误: 缺少参数: 日期字符串"
        return 1
    fi
    
    log_debug "utils_datetime" "判断是否为工作日(排除节假日): $date_str"
    
    # 首先判断是否为工作日
    if ! utils_datetime_is_workday "$date_str"; then
        return 1
    fi
    
    # 再判断是否为节假日
    if utils_datetime_is_holiday "$date_str"; then
        log_debug "utils_datetime" "工作日但为节假日: $date_str"
        return 1
    fi
    
    log_debug "utils_datetime" "工作日(非节假日): $date_str"
    return 0
}

# 函数: 计算工作日数量
# 参数: $1 - 开始日期, $2 - 结束日期, $3 - 是否排除节假日(可选,默认true)
# 返回: 0-成功, 1-失败
# 输出: 工作日数量(stdout)
function utils_datetime_count_workdays() {
    local start_date="$1"
    local end_date="$2"
    local exclude_holidays="${3:-true}"
    
    if [[ -z "$start_date" ]] || [[ -z "$end_date" ]]; then
        log_error "utils_datetime" "错误: 缺少参数: 开始日期和结束日期"
        return 1
    fi
    
    log_debug "utils_datetime" "计算工作日数量: $start_date -> $end_date (排除节假日: $exclude_holidays)"
    
    local current_date="$start_date"
    local workday_count=0
    
    # 验证日期格式
    if ! date -d "$start_date" >/dev/null 2>&1 || ! date -d "$end_date" >/dev/null 2>&1; then
        log_error "utils_datetime" "错误: 无效的日期格式"
        return 1
    fi
    
    # 确保开始日期不晚于结束日期
    local start_timestamp end_timestamp
    start_timestamp=$(date -d "$start_date" +%s)
    end_timestamp=$(date -d "$end_date" +%s)
    
    if [[ "$start_timestamp" -gt "$end_timestamp" ]]; then
        log_error "utils_datetime" "错误: 开始日期不能晚于结束日期"
        return 1
    fi
    
    # 逐日检查
    while [[ "$start_timestamp" -le "$end_timestamp" ]]; do
        current_date=$(date -d "@$start_timestamp" +%Y-%m-%d)
        
        local is_workday=false
        if [[ "$exclude_holidays" == "true" ]]; then
            if utils_datetime_is_business_day "$current_date"; then
                is_workday=true
            fi
        else
            if utils_datetime_is_workday "$current_date"; then
                is_workday=true
            fi
        fi
        
        if [[ "$is_workday" == "true" ]]; then
            ((workday_count++))
        fi
        
        start_timestamp=$((start_timestamp + UTILS_DATETIME_DAY))
    done
    
    echo "$workday_count"
    return 0
}

# 函数: 获取下一个工作日
# 参数: $1 - 基准日期, $2 - 是否排除节假日(可选,默认true)
# 返回: 0-成功, 1-失败
# 输出: 下一个工作日(stdout)
function utils_datetime_next_workday() {
    local base_date="$1"
    local exclude_holidays="${2:-true}"
    
    if [[ -z "$base_date" ]]; then
        log_error "utils_datetime" "错误: 缺少参数: 基准日期"
        return 1
    fi
    
    log_debug "utils_datetime" "获取下一个工作日: $base_date (排除节假日: $exclude_holidays)"
    
    local current_date="$base_date"
    local current_timestamp
    if ! current_timestamp=$(date -d "$base_date" +%s 2>/dev/null); then
        log_error "utils_datetime" "错误: 无效的日期格式: $base_date"
        return 1
    fi
    
    # 从下一天开始查找
    current_timestamp=$((current_timestamp + UTILS_DATETIME_DAY))
    
    # 最多查找30天
    local max_days=30
    local days_checked=0
    
    while [[ $days_checked -lt $max_days ]]; do
        current_date=$(date -d "@$current_timestamp" +%Y-%m-%d)
        
        local is_workday=false
        if [[ "$exclude_holidays" == "true" ]]; then
            if utils_datetime_is_business_day "$current_date"; then
                is_workday=true
            fi
        else
            if utils_datetime_is_workday "$current_date"; then
                is_workday=true
            fi
        fi
        
        if [[ "$is_workday" == "true" ]]; then
            echo "$current_date"
            return 0
        fi
        
        current_timestamp=$((current_timestamp + UTILS_DATETIME_DAY))
        ((days_checked++))
    done
    
    log_error "utils_datetime" "错误: 在$max_days天内未找到工作日"
    return 1
}

# 函数: 生成时间序列
# 参数: $1 - 开始时间, $2 - 结束时间, $3 - 间隔单位(second/minute/hour/day/week), $4 - 间隔数量
# 返回: 0-成功, 1-失败
# 输出: 时间序列(stdout,每行一个时间)
function utils_datetime_generate_sequence() {
    local start_time="$1"
    local end_time="$2"
    local unit="$3"
    local interval="$4"
    
    if [[ -z "$start_time" ]] || [[ -z "$end_time" ]] || [[ -z "$unit" ]] || [[ -z "$interval" ]]; then
        log_error "utils_datetime" "错误: 缺少参数: 开始时间、结束时间、间隔单位和间隔数量"
        return 1
    fi
    
    # 验证间隔数量
    if ! [[ "$interval" =~ ^[0-9]+$ ]]; then
        log_error "utils_datetime" "错误: 无效的间隔数量: $interval"
        return 1
    fi
    
    log_debug "utils_datetime" "生成时间序列: $start_time -> $end_time (间隔: $interval $unit)"
    
    local current_timestamp end_timestamp interval_seconds
    
    # 转换为时间戳
    if ! current_timestamp=$(date -d "$start_time" +%s 2>/dev/null); then
        log_error "utils_datetime" "错误: 无效的开始时间格式: $start_time"
        return 1
    fi
    
    if ! end_timestamp=$(date -d "$end_time" +%s 2>/dev/null); then
        log_error "utils_datetime" "错误: 无效的结束时间格式: $end_time"
        return 1
    fi
    
    # 计算间隔秒数
    case "$unit" in
        "second"|"seconds")
            interval_seconds=$interval
            ;;
        "minute"|"minutes")
            interval_seconds=$((interval * UTILS_DATETIME_MINUTE))
            ;;
        "hour"|"hours")
            interval_seconds=$((interval * UTILS_DATETIME_HOUR))
            ;;
        "day"|"days")
            interval_seconds=$((interval * UTILS_DATETIME_DAY))
            ;;
        "week"|"weeks")
            interval_seconds=$((interval * UTILS_DATETIME_WEEK))
            ;;
        *)
            log_error "utils_datetime" "错误: 不支持的时间单位: $unit"
            return 1
            ;;
    esac
    
    if [[ "$interval_seconds" -le 0 ]]; then
        log_error "utils_datetime" "错误: 无效的间隔时间"
        return 1
    fi
    
    # 生成序列
    while [[ "$current_timestamp" -le "$end_timestamp" ]]; do
        local current_time
        current_time=$(date -d "@$current_timestamp" "+$utils_datetime_default_format")
        echo "$current_time"
        current_timestamp=$((current_timestamp + interval_seconds))
    done
    
    return 0
}

# 函数: 获取月份的天数
# 参数: $1 - 年份, $2 - 月份
# 返回: 0-成功, 1-失败
# 输出: 天数(stdout)
function utils_datetime_days_in_month() {
    local year="$1"
    local month="$2"
    
    if [[ -z "$year" ]] || [[ -z "$month" ]]; then
        log_error "utils_datetime" "错误: 缺少参数: 年份和月份"
        return 1
    fi
    
    # 验证年份和月份格式
    if ! [[ "$year" =~ ^[0-9]{4}$ ]]; then
        log_error "utils_datetime" "错误: 无效的年份格式: $year"
        return 1
    fi
    
    if ! [[ "$month" =~ ^(0?[1-9]|1[0-2])$ ]]; then
        log_error "utils_datetime" "错误: 无效的月份格式: $month"
        return 1
    fi
    
    log_debug "utils_datetime" "获取月份天数: $year年$month月"
    
    # 使用date命令获取天数（更可靠的方法）
    local next_month
    if [[ "$month" == "12" ]]; then
        next_month="01"
        year=$((year + 1))
    else
        next_month=$(printf "%02d" $((month + 1)))
    fi
    
    local last_day
    if last_day=$(date -d "$year-$next_month-01 -1 day" +%d 2>/dev/null); then
        echo "$last_day"
        return 0
    else
        # 备用方法：使用cal命令
        local days
        if days=$(cal "$month" "$year" 2>/dev/null | grep -E '^[ 0-9]+$' | awk '{print NF}' | tail -1); then
            echo "$days"
            return 0
        fi
    fi
    
    log_error "utils_datetime" "错误: 无法获取月份天数"
    return 1
}

# 函数: 判断是否为闰年
# 参数: $1 - 年份
# 返回: 0-是闰年, 1-非闰年
function utils_datetime_is_leap_year() {
    local year="$1"
    
    if [[ -z "$year" ]]; then
        log_error "utils_datetime" "错误: 缺少参数: 年份"
        return 1
    fi
    
    # 验证年份格式
    if ! [[ "$year" =~ ^[0-9]{4}$ ]]; then
        log_error "utils_datetime" "错误: 无效的年份格式: $year"
        return 1
    fi
    
    log_debug "utils_datetime" "判断是否为闰年: $year"
    
    # 闰年规则：能被4整除且不能被100整除，或者能被400整除
    if [[ $((year % 4)) -eq 0 ]] && [[ $((year % 100)) -ne 0 ]] || [[ $((year % 400)) -eq 0 ]]; then
        log_debug "utils_datetime" "闰年: $year"
        return 0
    else
        log_debug "utils_datetime" "非闰年: $year"
        return 1
    fi
}

# 函数: 获取年龄
# 参数: $1 - 出生日期, $2 - 计算日期(可选,默认当前日期)
# 返回: 0-成功, 1-失败
# 输出: 年龄(stdout)
function utils_datetime_get_age() {
    local birth_date="$1"
    local calc_date="${2:-$(utils_datetime_today)}"
    
    if [[ -z "$birth_date" ]]; then
        log_error "utils_datetime" "错误: 缺少参数: 出生日期"
        return 1
    fi
    
    log_debug "utils_datetime" "计算年龄: $birth_date -> $calc_date"
    
    # 验证日期格式
    if ! date -d "$birth_date" >/dev/null 2>&1 || ! date -d "$calc_date" >/dev/null 2>&1; then
        log_error "utils_datetime" "错误: 无效的日期格式"
        return 1
    fi
    
    local birth_year calc_year birth_month calc_month birth_day calc_day
    
    birth_year=$(date -d "$birth_date" +%Y)
    birth_month=$(date -d "$birth_date" +%m)
    birth_day=$(date -d "$birth_date" +%d)
    
    calc_year=$(date -d "$calc_date" +%Y)
    calc_month=$(date -d "$calc_date" +%m)
    calc_day=$(date -d "$calc_date" +%d)
    
    # 计算年龄
    local age=$((calc_year - birth_year))
    
    # 如果还没到生日，年龄减1
    if [[ "$calc_month" -lt "$birth_month" ]] || \
       [[ "$calc_month" -eq "$birth_month" ]] && [[ "$calc_day" -lt "$birth_day" ]]; then
        age=$((age - 1))
    fi
    
    echo "$age"
    return 0
}

# 函数: 获取星座
# 参数: $1 - 月份, $2 - 日期
# 返回: 0-成功, 1-失败
# 输出: 星座名称(stdout)
function utils_datetime_get_zodiac() {
    local month="$1"
    local day="$2"
    
    if [[ -z "$month" ]] || [[ -z "$day" ]]; then
        log_error "utils_datetime" "错误: 缺少参数: 月份和日期"
        return 1
    fi
    
    # 验证月份和日期格式
    if ! [[ "$month" =~ ^(0?[1-9]|1[0-2])$ ]]; then
        log_error "utils_datetime" "错误: 无效的月份格式: $month"
        return 1
    fi
    
    if ! [[ "$day" =~ ^(0?[1-9]|[12][0-9]|3[01])$ ]]; then
        log_error "utils_datetime" "错误: 无效的日期格式: $day"
        return 1
    fi
    
    log_debug "utils_datetime" "获取星座: $month月$day日"
    
    # 转换为数字
    month=$((10#$month))
    day=$((10#$day))
    
    local zodiac=""
    
    # 星座日期范围
    if [[ ($month -eq 3 && $day -ge 21) || ($month -eq 4 && $day -le 19) ]]; then
        zodiac="白羊座"
    elif [[ ($month -eq 4 && $day -ge 20) || ($month -eq 5 && $day -le 20) ]]; then
        zodiac="金牛座"
    elif [[ ($month -eq 5 && $day -ge 21) || ($month -eq 6 && $day -le 21) ]]; then
        zodiac="双子座"
    elif [[ ($month -eq 6 && $day -ge 22) || ($month -eq 7 && $day -le 22) ]]; then
        zodiac="巨蟹座"
    elif [[ ($month -eq 7 && $day -ge 23) || ($month -eq 8 && $day -le 22) ]]; then
        zodiac="狮子座"
    elif [[ ($month -eq 8 && $day -ge 23) || ($month -eq 9 && $day -le 22) ]]; then
        zodiac="处女座"
    elif [[ ($month -eq 9 && $day -ge 23) || ($month -eq 10 && $day -le 23) ]]; then
        zodiac="天秤座"
    elif [[ ($month -eq 10 && $day -ge 24) || ($month -eq 11 && $day -le 22) ]]; then
        zodiac="天蝎座"
    elif [[ ($month -eq 11 && $day -ge 23) || ($month -eq 12 && $day -le 21) ]]; then
        zodiac="射手座"
    elif [[ ($month -eq 12 && $day -ge 22) || ($month -eq 1 && $day -le 19) ]]; then
        zodiac="摩羯座"
    elif [[ ($month -eq 1 && $day -ge 20) || ($month -eq 2 && $day -le 18) ]]; then
        zodiac="水瓶座"
    elif [[ ($month -eq 2 && $day -ge 19) || ($month -eq 3 && $day -le 20) ]]; then
        zodiac="双鱼座"
    else
        log_error "utils_datetime" "错误: 无效的日期范围"
        return 1
    fi
    
    echo "$zodiac"
    return 0
}

###############################################################################
# 帮助函数
###############################################################################

# 函数: 显示帮助信息
function utils_datetime_help() {
    cat << 'EOF'
日期时间处理工具 (utils_datetime.sh) - 使用说明

基础功能函数：
  utils_datetime_now [format]                    - 获取当前日期时间
  utils_datetime_today [format]                  - 获取当前日期
  utils_datetime_time [format]                   - 获取当前时间
  utils_datetime_timestamp                       - 获取Unix时间戳

格式转换函数：
  utils_datetime_convert <datetime> <in_fmt> <out_fmt> - 转换日期时间格式
  utils_datetime_from_timestamp <timestamp> [format]   - Unix时间戳转日期时间
  utils_datetime_to_timestamp <datetime>               - 日期时间转Unix时间戳

格式化输出函数：
  utils_datetime_format <datetime> <format>      - 格式化日期时间
  utils_datetime_relative <datetime>             - 获取相对时间描述

差值计算函数：
  utils_datetime_diff_seconds <start> <end>      - 计算两个日期时间的差值（秒）
  utils_datetime_diff_days <start> <end>         - 计算两个日期时间的差值（天）
  utils_datetime_add <datetime> <amount> <unit>  - 计算日期时间加减

时区处理函数：
  utils_datetime_set_timezone <timezone>         - 设置默认时区
  utils_datetime_get_timezone                    - 获取当前时区
  utils_datetime_convert_timezone <datetime> <timezone> [format] - 转换时区

增强功能函数：
  utils_datetime_is_workday <date>               - 判断是否为工作日
  utils_datetime_is_holiday <date>               - 判断是否为节假日
  utils_datetime_is_business_day <date>          - 判断是否为工作日(排除节假日)
  utils_datetime_count_workdays <start> <end> [exclude_holidays] - 计算工作日数量
  utils_datetime_next_workday <date> [exclude_holidays] - 获取下一个工作日
  utils_datetime_generate_sequence <start> <end> <unit> <interval> - 生成时间序列
  utils_datetime_days_in_month <year> <month>    - 获取月份的天数
  utils_datetime_is_leap_year <year>             - 判断是否为闰年
  utils_datetime_get_age <birth_date> [calc_date] - 获取年龄
  utils_datetime_get_zodiac <month> <day>        - 获取星座

参数说明：
  datetime     - 日期时间字符串
  format       - 日期时间格式（如：%Y-%m-%d %H:%M:%S）
  timestamp    - Unix时间戳
  amount       - 加减数量（正数或负数）
  unit         - 时间单位：second|minute|hour|day|week
  timezone     - 时区标识符（如：Asia/Shanghai、UTC）

常用格式：
  %Y-%m-%d %H:%M:%S  - ISO格式（默认）
  %Y-%m-%d           - 日期格式
  %H:%M:%S           - 时间格式
  %Y%m%d_%H%M%S      - 时间戳格式
  %Y-%m-%dT%H:%M:%S%z - RFC3339格式

使用示例：
  # 基础获取
  utils_datetime_now
  utils_datetime_today "%Y年%m月%d日"
  utils_datetime_timestamp
  
  # 格式转换
  utils_datetime_convert "2025-01-27 10:30:00" "%Y-%m-%d %H:%M:%S" "%Y/%m/%d"
  utils_datetime_from_timestamp 1737952200
  utils_datetime_to_timestamp "2025-01-27 10:30:00"
  
  # 差值计算
  utils_datetime_diff_days "2025-01-01" "2025-01-27"
  utils_datetime_add "2025-01-27" "7" "day"
  
  # 时区处理
  utils_datetime_set_timezone "Asia/Shanghai"
  utils_datetime_convert_timezone "2025-01-27 10:30:00" "UTC"
  
  # 增强功能
  utils_datetime_is_workday "2025-01-27"
  utils_datetime_count_workdays "2025-01-01" "2025-01-31"
  utils_datetime_next_workday "2025-01-25"
  utils_datetime_generate_sequence "2025-01-01 00:00:00" "2025-01-01 12:00:00" "hour" "2"
  utils_datetime_get_age "1990-01-01"
  utils_datetime_get_zodiac "1" "27"

注意事项：
  1. 本模块为纯日期时间处理工具，不包含业务逻辑
  2. 所有函数都支持时区设置
  3. 日期时间字符串格式需要符合系统date命令要求
  4. 时区标识符需要符合标准时区数据库格式

EOF
}

###############################################################################
# 简单日志函数（如果外部日志模块不可用）
###############################################################################

if ! command -v log_debug >/dev/null 2>&1; then
    function log_debug() { 
        local module="${1:-}"
        shift
        echo "[DEBUG] [$module] $*" >&2
    }
fi

if ! command -v log_info >/dev/null 2>&1; then
    function log_info() {
        local module="${1:-}"
        shift
        echo "[INFO]  [$module] $*" >&2
    }
fi

if ! command -v log_warn >/dev/null 2>&1; then
    function log_warn() {
        local module="${1:-}"
        shift
        echo "[WARN]  [$module] $*" >&2
    }
fi

if ! command -v log_error >/dev/null 2>&1; then
    function log_error() {
        local module="${1:-}"
        shift
        echo "[ERROR] [$module] $*" >&2
    }
fi